using System;
using System.Collections;
using System.IO;
using System.Text.RegularExpressions;

namespace FileNameChanger
{
	public class FileNameChanger
	{
		private string m_startPath = String.Empty;
		private bool m_traverseSubdirectory = false;
		private IList m_changePattern;
		private string m_endExtension = String.Empty;
		private string m_outputDirectory = String.Empty;
		private IList m_removePattern;
		private IList m_removeStringPattern;
		private IList m_errors;
		int m_totalFiles = 0;
		int m_copiedFiles = 0;
		int m_errorFiles = 0;
		string m_categoryDirectory;

		bool m_isCategoryFileNeeded = false;
		int m_categoryIndexFromDirectoryName = 1;

		public FileNameChanger()
		{
			m_changePattern = new ArrayList();
			m_removePattern = new ArrayList();
			m_removeStringPattern = new ArrayList();
			m_errors = new ArrayList();
		}

		public FileNameChanger(string startPath)
		{
			m_changePattern = new ArrayList();
			m_removePattern = new ArrayList();
			m_removeStringPattern = new ArrayList();
			this.StartingPath = startPath;
			m_errors = new ArrayList();
		}


		public string StartingPath
		{
			get { return m_startPath; }
			set { m_startPath = value; }

		}

		public bool TraverseSubdirectory
		{
			get { return m_traverseSubdirectory; }
			set { m_traverseSubdirectory = value; }
		}

		public bool IsCategoryFileNeeded
		{
			get { return m_isCategoryFileNeeded; }
			set { m_isCategoryFileNeeded = value; }
		}

		public int CategoryIndexFromDirectoryName
		{
			get { return m_categoryIndexFromDirectoryName; }
			set { m_categoryIndexFromDirectoryName = value; }
		}

		public void AddChangePatterns(string [] changePattern)
		{
      if (changePattern != null)m_changePattern.Add(changePattern);
		}

		public void AddRemoveStringPattern(string pattern)
		{
			m_removeStringPattern.Add(pattern);
		}

		public void AddRemovePatterns(char removePattern)
		{
			m_removePattern.Add(removePattern);
		}

		public string EndExtension
		{
			get { return m_endExtension; }
			set { 
				m_endExtension = "." + value; 
			}
		}

		public string OutputDirectory
		{
			get { return m_outputDirectory; }
			set { 
				m_outputDirectory = value; 
				if (m_outputDirectory[m_outputDirectory.Length - 1] != '\\') 
					m_outputDirectory = m_outputDirectory + "\\";
			}
		}

		public void Start()
		{
			m_totalFiles = 0;
			m_copiedFiles = 0;
			m_errorFiles = 0;

			m_errors.Clear();
			if (m_startPath == String.Empty) m_startPath = Directory.GetCurrentDirectory();

			string [] subdirectory = null;
			if (m_traverseSubdirectory) subdirectory = Directory.GetDirectories(m_startPath);

			StreamWriter writer = null;
			try 
			{
				m_categoryDirectory = (m_outputDirectory != String.Empty)  ? m_outputDirectory : Directory.GetCurrentDirectory();
				if (m_categoryDirectory[m_categoryDirectory.Length - 1] != '\\' ) m_categoryDirectory += "\\";
				string path = m_categoryDirectory  + "category.txt";
				writer = new StreamWriter( path);
				Console.WriteLine("Category file was created successfully : " + path);
			}
			catch(Exception ex)
			{
				Console.WriteLine("Category file error " + ex.Message);
				if (writer != null) writer.Close();
				writer = null;
			}

			this.TraverseDirectories(m_startPath,writer);

			Console.WriteLine("Total files found : " + m_totalFiles);
			Console.WriteLine("Copied files : " + m_copiedFiles);
			Console.WriteLine("Error files : " + m_errorFiles);
			int index = 1;
			foreach (string ex in m_errors)
			{
				Console.WriteLine(ex);
				index++;
			}

			if (writer != null) writer.Close();
		}

		private void TraverseDirectories(string subdirectory,StreamWriter writer)
		{
			Console.WriteLine("Entered " + subdirectory);
			string [] files = Directory.GetFiles(subdirectory);
			this.ChangeFiles(files,writer);

			if (subdirectory.Length == 0) return;

			string [] subdirectories = Directory.GetDirectories(subdirectory);

			foreach(string subdirectoryName in subdirectories)
			{
				files = Directory.GetFiles(subdirectoryName);
				this.TraverseDirectories(subdirectoryName,writer);
			}
		}

		private void ChangeFiles(string [] files,StreamWriter writer)
		{
			string from;
			string to;
			string result;
			
			foreach (string file in files)
			{
				result = file;
				foreach (string removeStringPattern in m_removeStringPattern)
				{
					result = this.RemoveStringPattern(removeStringPattern,result);
				}
				foreach(char removePattern in m_removePattern)
				{
					result = this.RemoveCharacter(removePattern,result);
				}
				foreach(string [] changePattern in m_changePattern)
				{
          from = changePattern[0];
					to = changePattern[1];
					result = result.Replace(from,to);
				}

				if (m_endExtension != String.Empty)
				{
					result += m_endExtension;
				}

				if (result == file) continue;

				if (m_outputDirectory != String.Empty)
				{
					FileInfo info = new FileInfo(result);
					result = m_outputDirectory + info.Name;
				}
				
				try
				{
					File.Copy(file,result);
					++m_copiedFiles;
					if (writer != null)
					{
						FileInfo info = new FileInfo(result);
						FileInfo info2 = new FileInfo(file);
						string category = this.GetCategoryDirectory(info2.DirectoryName);
						if (category != null) writer.WriteLine(info.Name + "\t" + category);
						else Console.WriteLine("Error retrieving category for " + result);
					}
				}
				catch(Exception ex)
				{
         m_errors.Add(file + " " + result + " " + ex.Message);
					++m_errorFiles;
				}
				++m_totalFiles;
			}

			
		}

		private string RemoveStringPattern(string pattern, string oldFile)
		{
			string file = oldFile;
			int index;
			while ((index = file.IndexOf(pattern,0,file.Length)) >=0)
			{
				if (index == 0) 
				{
					if (file.Length > pattern.Length) file = file.Substring(index + pattern.Length);
					else return String.Empty;
				}
				else
				{
					string firstPart = file.Substring(0,index);
					string lastPart;
					if (index + pattern.Length < file.Length)
					{
						lastPart = file.Substring(index + pattern.Length,file.Length - (index + pattern.Length));
						file = firstPart + lastPart;
					}
					else file = firstPart;
				}
			}
			return file;
		}

		private string RemoveCharacter(char pattern, string oldFile)
		{
			string file = oldFile;
			int index;
			while ((index = file.IndexOf(pattern)) >= 0)
			{
				if (index == 0) 
				{
					if (file.Length > 1) file = file.Substring(index + 1);
					else return String.Empty;
				}
				else if (index == file.Length - 1)
				{
					file = file.Substring(0,file.Length - 1);
				}
				else
				{
           string firstPart = file.Substring(0,index);
					 string lastPart = file.Substring(index + 1,file.Length - (index + 1));
					file = firstPart + lastPart;
				}
			}
			return file;
		}

		private string GetCategoryDirectory(string directory)
		{
      string category;

			string tempPart = "no category";

			int index;
			if (m_categoryIndexFromDirectoryName == 1)
			{
				index = directory.LastIndexOf("\\");
				if (index <= 0) return null;
				category = directory.Substring(index + 1);
			}
			else
			{
				int counter = m_categoryIndexFromDirectoryName;
				while (counter > 0)
				{
					index = directory.LastIndexOf("\\");
					if (index < 0) return null;
					tempPart = directory.Substring(index+1);
					directory = directory.Substring(0,index);
					counter--;
				}

				category = tempPart;
		  }

			return category;
		}
	}
}
